package com.autumn.platform.web.jsonbody;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;

import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

import com.autumn.platform.web.jsonbody.serial.config.IJsonSerialConfig;
import com.autumn.platform.web.jsonbody.serial.config.JsonSerialConfigContext;
import com.autumn.platform.web.jsonbody.serial.stdexp.JsonBeanSerializerFactory;
import com.autumn.platform.web.jsonbody.serial.stdexp.JsonClassIntrospector;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.ser.BasicSerializerFactory;

public abstract class JsonUtils {

    /**
     * JSON对象
     */
    private static ObjectMapper mapper = null;

    /**
     * 获取单例ObjectMapper实例
     * 
     * @return ObjectMapper单实例
     */
    public static ObjectMapper getSingleonObjectMapper() {
        if (null == mapper) {
            synchronized (JsonUtils.class) {
                if (null == mapper) {
                    ObjectMapper mapper = getObjectMapper();
                    JsonUtils.mapper = mapper;
                }
            }
        }
        return mapper;
    }

    /**
     * 获取新的ObjectMapper实例
     * 
     * @return ObjectMapper 新实例
     */
    public static ObjectMapper getObjectMapper() {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        jsonCustomizer(builder);

        ObjectMapper mapper = builder.build();

        // 使用自定义的类侦测器
        JsonClassIntrospector jci = new JsonClassIntrospector();
        mapper.setConfig(mapper.getSerializationConfig().with(jci));
        // 使用自定义的序列化工厂类（目前只替换了Map的序列化）
        BasicSerializerFactory sf = (BasicSerializerFactory) mapper.getSerializerFactory();
        mapper.setSerializerFactory(new JsonBeanSerializerFactory(sf.getFactoryConfig()));
        return mapper;
    }

    /**
     * 自定义JSON配置
     * 
     * @param builder
     */
    public static void jsonCustomizer(Jackson2ObjectMapperBuilder builder) {
        builder.featuresToEnable(JsonParser.Feature.ALLOW_SINGLE_QUOTES, // 允许使用单引号
                JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, // 允许字段名不用引号
                JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, // 允许字段名不用引号
                DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, //
                MapperFeature.AUTO_DETECT_GETTERS, //
                MapperFeature.AUTO_DETECT_IS_GETTERS)//
                .featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, // 忽略字符串有java中没有的属性
                        SerializationFeature.FAIL_ON_EMPTY_BEANS, //
                        SerializationFeature.FAIL_ON_SELF_REFERENCES, // 自引用时是否失败
                        SerializationFeature.INDENT_OUTPUT, // 格式化输出
                        MapperFeature.AUTO_DETECT_FIELDS)//
                .serializationInclusion(Include.NON_NULL);// 是否包括null值属性
    }

    /**
     * 根据配置和包装对象序列化对象
     * 
     * @param target 原始对象
     * @param configs 序列化配置
     * @return json字符串
     * @throws JsonProcessingException
     */
    public static String serialize(Object target, IJsonSerialConfig... configs) throws JsonProcessingException {
        try {
            JsonSerialConfigContext.addSerialConfigs(configs);
            return getContextObjectMapper().writeValueAsString(target);
        } finally {
            JsonSerialConfigContext.remove();
        }
    }

    /**
     * 根据配置和包装对象序列化对象至输出流
     * 
     * @param out 输出流
     * @param target 原始对象
     * @param configs 序列化配置
     * @throws IOException
     * @throws JsonMappingException
     * @throws JsonGenerationException
     */
    public static void serialize(OutputStream out, Object target, IJsonSerialConfig... configs) throws JsonGenerationException, JsonMappingException, IOException {
        try {
            JsonSerialConfigContext.addSerialConfigs(configs);
            getContextObjectMapper().writeValue(out, target);
        } finally {
            JsonSerialConfigContext.remove();
        }
    }

    /**
     * 将Json字符串转变为Map<String, Object>
     * 
     * @param jsonString json字符串
     * @return Map<String, Object>对象
     * @throws IOException
     * @throws JsonMappingException
     * @throws JsonParseException
     */
    public static Map<String, Object> deserial2Map(String jsonString) throws JsonParseException, JsonMappingException, IOException {
        return getSingleonObjectMapper().readValue(jsonString, new TypeReference<Map<String, Object>>() {});
    }

    /**
     * 将Json字符串转变为List<Map<String, Object>>
     * 
     * @param jsonString json字符串
     * @return List<Map<String, Object>>对象
     * @throws IOException
     * @throws JsonMappingException
     * @throws JsonParseException
     */
    public static List<Map<String, Object>> deserial2ListMap(String jsonString) throws JsonParseException, JsonMappingException, IOException {
        return getSingleonObjectMapper().readValue(jsonString, new TypeReference<List<Map<String, Object>>>() {});
    }

    /**
     * 反序列化对象
     * 
     * @param content Json字符串
     * @param list LIST泛型类型
     * @return List<T>
     * @throws IOException
     * @throws JsonMappingException
     * @throws JsonParseException
     */
    public static <T> List<T> deserialize2ListBean(String content, Class<T> cls) throws JsonParseException, JsonMappingException, IOException {
        return getSingleonObjectMapper().readValue(content, new TypeReference<List<T>>() {});
    }

    /**
     * 反序列化对象
     * 
     * @param content Json字符串
     * @param cls 返回的类对象
     * @return cls类实例
     * @throws IOException
     * @throws JsonMappingException
     * @throws JsonParseException
     */
    public static <T> T deserialize2Bean(String content, Class<T> cls) throws JsonParseException, JsonMappingException, IOException {
        return getSingleonObjectMapper().readValue(content, cls);
    }

    /**
     * 反序列化对象
     * 
     * @param stream 输入流
     * @param list LIST泛型类型
     * @return List<T>
     * @throws IOException
     * @throws JsonMappingException
     * @throws JsonParseException
     */
    public static <T> List<T> deserialize2ListBean(InputStream stream, Class<T> cls) throws JsonParseException, JsonMappingException, IOException {
        return getSingleonObjectMapper().readValue(stream, new TypeReference<List<T>>() {});
    }

    /**
     * 反序列化对象
     * 
     * @param stream 输入流
     * @param cls 返回的类对象
     * @return
     * @throws IOException
     * @throws JsonMappingException
     * @throws JsonParseException
     */
    public static <T> T deserialize2Bean(InputStream stream, Class<T> cls) throws JsonParseException, JsonMappingException, IOException {
        return getSingleonObjectMapper().readValue(stream, cls);
    }

    public static ObjectMapper getContextObjectMapper() {
        if (JsonSerialConfigContext.isValid()) {
            return getObjectMapper();
        } else {
            return getSingleonObjectMapper();
        }
    }
}
